package com.shangxian.giveithome.service.impl;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.shangxian.giveithome.code.CommonCode;
import com.shangxian.giveithome.code.ImgFeiCode;
import com.shangxian.giveithome.controller.MechanismServer;
import com.shangxian.giveithome.entity.*;
import com.shangxian.giveithome.exception.ExceptionUtils;
import com.shangxian.giveithome.exception.ImgException;
import com.shangxian.giveithome.mapper.ImgFeiMapper;
import com.shangxian.giveithome.mapper.ImgMapper;
import com.shangxian.giveithome.mapper.PetQrCodeMapper;
import com.shangxian.giveithome.result.Result;
import com.shangxian.giveithome.service.ApiService;
import com.shangxian.giveithome.service.ImgFeiService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.csource.common.MyException;
import org.csource.common.NameValuePair;
import org.csource.fastdfs.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import static com.shangxian.giveithome.code.QrCode.FREQUENCY_ERROR;
import static com.shangxian.giveithome.code.QrCode.WX_PAGE_NOT_DATA;
import static com.shangxian.giveithome.properties.ImageProperties.IMG_RESOURCE;
import static com.shangxian.giveithome.properties.ImageProperties.IMG_SIZE;


@Slf4j
@Service
public class ImgFeiServiceImpl implements ImgFeiService {

    @Resource
    private ImgFeiMapper imgFeiMapper;

    @Resource
    private ImgMapper imgMapper;

    @Resource
    private MechanismServer mechanismServer;

    @Resource
    private PetQrCodeMapper petQrCodeMapper;

    @Autowired
    private RestTemplate restTemplate;

    @Resource
    private ApiService apiService;




    /**
     * 根基收容id集合查询图片集合
     *
     * @param ids
     * @return
     */
    @Override
    public List<Img> queryAsylumImgs(List<Long> ids) {
        List<Img> imgS = imgFeiMapper.queryAsylumImgS(ids);
        if (CollectionUtils.isEmpty(imgS)) {
            return new ArrayList<>();
        }
        return imgS;
    }

    /**
     * 根据id查询图片数据
     *
     * @param imgIds
     * @return
     */
    @Override
    public List<Img> queryByIds(List<Long> imgIds) {
        List<Img> imgs = imgFeiMapper.queryByImgIds(imgIds);
        if (CollectionUtils.isEmpty(imgs)) {
            return new ArrayList<>();
        }
        return imgs;
    }

    /**
     * 删除文件
     *
     * @param header
     * @param img
     */
    @Override
    @Transactional
    public Result delete(UserDetails header, List<Img> img) {
        if (CollectionUtils.isEmpty(img)) {
            //该数据为空
            return Result.error(ImgFeiCode.FILE_NOT_NULL);
        }
        //若是用户
        if (!header.getMechanismStatus()) {
            for (Img img1 : img) {
                if (!img1.getUsId().equals(header.getId())) {
                    //用户不匹配
                    return Result.error(ImgFeiCode.USER_NOT_PRE);
                }
            }
        } else {
            //查询机构id=收容id
            Long aLong = mechanismServer.queryById(header.getId());
            if (aLong == -1L) {
                //没有查询到相关数据
                return Result.error(ImgFeiCode.MECHANISM_NOT_DATA);
            }
            for (Img img1 : img) {
                if (!img1.getAsylumId().equals(aLong)) {
                    //机构不匹配
                    return Result.error(ImgFeiCode.MECHANISM_NOT_PRE);
                }
            }
        }
        imgMapper.deleteById(img);
        deletes(img);
        return Result.success(CommonCode.DELETE_SUCCESS);
    }

    /**
     * 新增
     *
     * @param header
     * @param id
     * @param multipartFile
     * @return
     */
    @Override
    @Transactional
    public Img inset(UserDetails header, Long id, MultipartFile multipartFile) {
        if (!checkFileSize(multipartFile.getSize(), IMG_SIZE, "M")) {
            ExceptionUtils.error(ImgFeiCode.FILE_SIZE);
        }
        String src_file_name = multipartFile.getOriginalFilename();
        String[] strArray = src_file_name.split("\\.");
        String ext_Name = strArray[strArray.length - 1];
        String file_Name = strArray[0];
        byte[] bytes = null;
        try {
            bytes = multipartFile.getBytes();
        } catch (IOException e) {
            log.error("【获取文件异常】");
            ExceptionUtils.error(ImgFeiCode.UPLOAD_ERROR);
        }
        String filePath = uploadFile(bytes, ext_Name, file_Name);
        if (StringUtils.isEmpty(filePath)) {
            log.error("【上传异常】");
            ExceptionUtils.error(ImgFeiCode.UPLOAD_ERROR);
        }
        Long imgId = id;
        Img img = new Img();
        img.setPath(filePath);
        //是否为机构
        if (!header.getMechanismStatus()) {
            img.setUsId(header.getId());
        } else {
            img.setAsylumId(header.getMechanism().getId());
        }
        if (id != null) {
            img.setId(imgId);
            imgMapper.saveById(img);
        } else {
            if (!header.getMechanismStatus())
                imgMapper.save(img);
            else
                imgMapper.saveMechanism(img);
        }
        Long aLong = imgMapper.queryByIds(img.getId());
        img.setKeyId(aLong);
        //img.setId(null);
        return img;
    }

    /**
     * 根据id查询图片集合
     *
     * @param imgId
     * @return
     */
    @Override
    public List<Img> queryByImages(Long imgId) {
        return imgFeiMapper.queryImages(imgId);
    }

    /**
     * 查询是否有活动二维码
     *
     * @param acId
     * @return
     */
    @Override
    public RqCode queryRecode(Long acId) {
        RqCode rqCode = imgFeiMapper.queryRqCode(acId);
        if (rqCode == null) {
            rqCode = new RqCode();
        }
        return rqCode;
    }

    /**
     * 保存活动二维码数据
     *
     * @param rqCode
     * @return
     */
    @Override
    @Transactional
    public String saveRqcode(RqCode rqCode) {
        try {
            File file = new File(rqCode.getPath());
            InputStream inputStream = new FileInputStream(file);
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int len;
            byte[] dataBytes;
            while ((len = inputStream.read(buffer)) != -1) {
                baos.write(buffer, 0, len);
            }
            baos.flush();
            dataBytes = baos.toByteArray();
            String strings = uploadFile(dataBytes, "jpg", rqCode.getId() + "qr");
            rqCode.setPath(strings);
            inputStream.close();
            baos.close();
            if (!file.isDirectory())
                file.delete();
        } catch (Exception e) {
            e.printStackTrace();
        }
        imgFeiMapper.saveRq(rqCode);
        return rqCode.getPath();
    }

    /**
     * 删除二维码
     *
     * @param id
     */
    @Override
    @Transactional
    public Integer deleteRq(Long id) {
        RqCode rqCode = imgFeiMapper.queryRqCode(id);
        if (rqCode == null) {
            return null;
        }
        Integer deleteRqCode = imgFeiMapper.deleteRqCode(rqCode.getId());
        if (deleteRqCode == 0) {
            ExceptionUtils.error(CommonCode.DATA_ERRORS);
        }
        deleteFile(rqCode.getPath());
        return deleteRqCode;
    }

    /**
     * 根据路径删除文件
     *
     * @param path
     */
    @Override
    public void deletePath(String path) {
        deleteFile(path);
    }

    @Override
    @Transactional
    public Result deleteMe(Long me_id, List<Img> imgs) {
        if (CollectionUtils.isEmpty(imgs)) {
            //该数据为空
            return Result.error(ImgFeiCode.FILE_NOT_NULL);
        }

        for (Img img1 : imgs) {
            if (!img1.getAsylumId().equals(me_id)) {
                //机构不匹配
                return Result.error(ImgFeiCode.MECHANISM_NOT_PRE);
            }
        }
        imgMapper.deleteByKey_Id(imgs);
        deletes(imgs);
        return Result.success(CommonCode.DELETE_SUCCESS);
    }

    @Override
    public RqCode queryRecodeMe(Long meId) {
        RqCode rqCode = imgFeiMapper.queryRqCodeMe(meId);
        if (rqCode == null) {
            rqCode = new RqCode();
        }
        return rqCode;
    }

    @Override
    @Transactional
    public String saveRqcodeMe(RqCode rqCode) {
        try {
            File file = new File(rqCode.getPath());
            InputStream inputStream = new FileInputStream(file);
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int len;
            byte[] dataBytes;
            while ((len = inputStream.read(buffer)) != -1) {
                baos.write(buffer, 0, len);
            }
            baos.flush();
            dataBytes = baos.toByteArray();
            String strings = uploadFile(dataBytes, "jpg", rqCode.getId() + "meRq");
            rqCode.setPath(strings);
            inputStream.close();
            baos.close();
            if (!file.isDirectory())
                file.delete();
        } catch (Exception e) {
            e.printStackTrace();
        }
        imgFeiMapper.saveRqMe(rqCode);
        return rqCode.getPath();

    }

    /**
     * 获取宠物二维码图片
     * @param wxCodeUnLimit
     * @return
     */
    @Override
    @Transactional
    public String queryPetQrCode(WxCodeUnLimit wxCodeUnLimit) {
        Long petId = Long.valueOf(wxCodeUnLimit.getScene());
        String path  = petQrCodeMapper.queryQrCodePath(petId);
        // 小程序码路径存在，且该小程序码在服务器中
        if (path != null && netImgIsExists(path)) {
            return path;
        }
        // 生成小程序码
        byte[] byteArray = createQRCode(wxCodeUnLimit);
        // 上传图片
        path = uploadFile(byteArray, "jpg", petId + "wxQrCode");
        PetQrCode petQrCode = new PetQrCode(petId, path);
        petQrCodeMapper.updateQrCode(petQrCode);
        return path;
    }







    // 获取小程序码
    private byte[] createQRCode(WxCodeUnLimit wxCodeUnLimit) {
        String access_token = apiService.getAccessToken();
        wxCodeUnLimit.setAccess_token(access_token);
        String url = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=" +
                access_token;
        ResponseEntity<byte[]> stringResponseEntity =
                restTemplate.postForEntity(url, wxCodeUnLimit, byte[].class);
        byte[] byteArray = stringResponseEntity.getBody();
        String wxreturn = new String(byteArray);
        // 小程序码获取失败
        if (wxreturn.indexOf("errcode") != -1) {
            JSONObject json = JSONObject.parseObject(wxreturn);
            Integer code = json.getInteger("errcode");
            if (code.equals(WX_PAGE_NOT_DATA.code())) {
                ExceptionUtils.error(WX_PAGE_NOT_DATA);
            } else if (code.equals(FREQUENCY_ERROR.code())) {
                ExceptionUtils.error(FREQUENCY_ERROR);
            }
        }
        return byteArray;
    }

    /**
     * 网络图片是否存在
     * @return
     */
    public static Boolean netImgIsExists(String filePath) {
        try {
            URL url = new URL(IMG_RESOURCE + filePath);
            HttpURLConnection urlcon2 = (HttpURLConnection) url.openConnection();
            urlcon2.setConnectTimeout(20000); // 设置连接主机超时（单位：毫秒）
            urlcon2.setReadTimeout(20000); // 设置从主机读取数据超时（单位：毫秒）
            int code = urlcon2.getResponseCode();
            if (code == 200 || code == 304) {
                String contentType = urlcon2.getHeaderField("Content-Type");
                if (contentType.contains("image")) {
                    return true;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
        return false;
    }


    /**
     * 删除文件
     *
     * @param filePath
     * @return
     */
    private Boolean deleteFile(String filePath) {
        try {
            // 链接FastDFS服务器，创建tracker和Stroage
            ClientGlobal.initByProperties("fastdfs.properties");
            TrackerClient trackerClient = new TrackerClient();
            TrackerServer trackerServer = trackerClient.getTrackerServer();
            String storageServerIp = getStorageServerIp(trackerClient, trackerServer);
            StorageServer storageServer = getStorageServer(storageServerIp);
            StorageClient storageClient = new StorageClient(trackerServer, storageServer);
            int i = storageClient.delete_file("group1", StringUtils.substringAfter(filePath, "group1/"));
            log.info(String.valueOf(i));
            if (i != 0) {
                log.info("删除失败");
                return false;
            }
        } catch (Exception e) {
            log.error("删除文件异常");
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 文件大小限制
     *
     * @param len
     * @param size
     * @param unit
     * @return
     */
    private static boolean checkFileSize(Long len, int size, String unit) {
        double fileSize = 0;
        if ("B".equals(unit.toUpperCase())) {
            fileSize = (double) len;
        } else if ("K".equals(unit.toUpperCase())) {
            fileSize = (double) len / 1024;
        } else if ("M".equals(unit.toUpperCase())) {
            fileSize = (double) len / 1048576;
        } else if ("G".equals(unit.toUpperCase())) {
            fileSize = (double) len / 1073741824;
        }
        if (fileSize > size) {
            return false;
        }
        return true;
    }

    /**
     * 删除封装
     *
     * @param img
     * @return
     */
    public Result deletes(List<Img> img) {
        for (Img img1 : img) {
            Boolean aBoolean = deleteFile(img1.getPath());
            if (!aBoolean) {
                //删除失败
                Result result = new Result(ImgFeiCode.DELETE_ERROR);
                throw new ImgException(result);
            }
        }
        return Result.error(CommonCode.DELETE_SUCCESS);
    }

    /**
     * 得到Storage服务
     *
     * @param storageIp
     * @return 返回Storage服务
     */
    private static StorageServer getStorageServer(String storageIp) {
        StorageServer storageServer = null;
        if (storageIp != null && !("").equals(storageIp)) {
            try {
                // ip port store_path下标
                storageServer = new StorageServer(storageIp, 23000, 0);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return storageServer;
    }

    /**
     * 获得可用的storage IP
     *
     * @param trackerClient
     * @param trackerServer
     * @return 返回storage IP
     */
    private static String getStorageServerIp(TrackerClient trackerClient, TrackerServer trackerServer) {
        String storageIp = null;
        if (trackerClient != null && trackerServer != null) {
            try {
                StorageServer storageServer = trackerClient.getStoreStorage(trackerServer, "group1");
                storageIp = storageServer.getInetSocketAddress().getAddress().getHostAddress();
            } catch (IOException | MyException e) {
                e.printStackTrace();
            }
        }
        return storageIp;
    }


    /**
     * 上传文件
     *
     * @param bytes
     * @param ext_Name
     * @param file_Name
     * @return
     */
    private String uploadFile(byte[] bytes, String ext_Name, String file_Name) {
        StringBuilder stringBuilder = new StringBuilder();
        try {
            ClientGlobal.initByProperties("fastdfs.properties");
            TrackerClient trackerClient = new TrackerClient();
            TrackerServer trackerServer = trackerClient.getTrackerServer();
            String storageServerIp = getStorageServerIp(trackerClient, trackerServer);
            StorageServer storageServer = getStorageServer(storageServerIp);
            StorageClient storageClient = new StorageClient(trackerServer, storageServer);
            NameValuePair[] pairs = new NameValuePair[1];
            pairs[0] = new NameValuePair(file_Name, ext_Name);
            String[] strings = storageClient.upload_file(bytes, ext_Name, null);
            stringBuilder.append(StrUtil.join("/", (Object) strings));
        } catch (IOException | MyException e) {
            ExceptionUtils.error(ImgFeiCode.UPLOAD_ERROR);
        }
        return stringBuilder.toString();
    }

    // 迁移数据时，图片迁移调用
    public String moveFileUpload(File file) {
        if (!checkFileSize(file.length(), IMG_SIZE, "M")) {
            ExceptionUtils.error(ImgFeiCode.FILE_SIZE);
        }
        String src_file_name = file.getName();
        String[] strArray = src_file_name.split("\\.");
        String ext_Name = strArray[strArray.length - 1];
        String file_Name = strArray[0];

        ByteArrayOutputStream bos = new ByteArrayOutputStream((int) file.length());
        BufferedInputStream in = null;
        byte[] bytes = null;
        try {
            in = new BufferedInputStream(new FileInputStream(file));
            int buf_size = 1024;
            byte[] buffer = new byte[buf_size];
            int len = 0;
            while (-1 != (len = in.read(buffer, 0, buf_size))) {
                bos.write(buffer, 0, len);
            }
            bytes = bos.toByteArray();
        } catch (IOException e) {
            log.error("【获取文件异常】");
            ExceptionUtils.error(ImgFeiCode.UPLOAD_ERROR);
        } finally {
            try {
                in.close();
                bos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        String filePath = uploadFile(bytes, ext_Name, file_Name);
        if (StringUtils.isEmpty(filePath)) {
            log.error("【上传异常】");
            ExceptionUtils.error(ImgFeiCode.UPLOAD_ERROR);
        }
        return filePath;
    }

    // 迁移数据时，图片迁移调用
    public String moveFileUpload(byte[] bytes, String ext_Name, String file_Name) {
        if (!checkFileSize(Long.valueOf(bytes.length), IMG_SIZE, "M")) {
            ExceptionUtils.error(ImgFeiCode.FILE_SIZE);
        }
        String filePath = uploadFile(bytes, ext_Name, file_Name);
        if (StringUtils.isEmpty(filePath)) {
            log.error("【上传异常】");
            ExceptionUtils.error(ImgFeiCode.UPLOAD_ERROR);
        }
        return filePath;
    }


}
